package cn.uaa.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;

/**
 * 授权服务器配置
 *
 * @author Mxb
 * @version 1.0
 * @date 2020/7/27 17:15
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private TokenStore tokenStore;


    /**
     * 3，令牌访问端点的安全策略  安全约束
     * 申请令牌url
     *
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //super.configure(security);
        security.tokenKeyAccess("permitAll()") //
                .checkTokenAccess("permitAll")  // 检测令牌
                .allowFormAuthenticationForClients();  //表单认证，申请令牌
    }

    /**
     * 1，配置客户端详细 信息服务
     *
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //super.configure(clients);
        // 暂时使用内存方式
        clients.inMemory() //
                .withClient("c1")  //client_id客户端id
                .secret(new BCryptPasswordEncoder().encode("secret"))   //客户端秘钥
                .resourceIds("res1") // 资源列表
                .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token") //允许授权类型
                .scopes("all")  //允许的授权范围
                .autoApprove(false) //跳转到授权页面
                // 加上验证回调地址
                .redirectUris("http://www.baidu.com");
    }

    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;


    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     *2，令牌访问端点，令牌服务
     *
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager)  //密码模式需要  令牌管理器
                .authorizationCodeServices(authorizationCodeServices)  //授权码模式需要
                .tokenServices(tokenServices())   //令牌管理服务
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);   //允许post提交

    }

    /**
     * 客户端详情 服务
     */
    @Autowired
    private ClientDetailsService clientDetailsService;

    /**
     * 2，令牌管理服务
     *
     * @return
     */
    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        services.setClientDetailsService(clientDetailsService); //客户端详细信息服务
        services.setSupportRefreshToken(true); //是否支持 产生刷新令牌

        services.setTokenStore(tokenStore); //令牌存储策略

        services.setAccessTokenValiditySeconds(7200); //令牌默认有效期2小时
        services.setRefreshTokenValiditySeconds(259200); //刷新令牌默认有效期3天

        return services;
    }

    /**
     * 设置授权码模式的 授权码如何存取，暂时采用内存方式
     *
     * @return
     */
    @Bean
    public AuthorizationCodeServices authorizationCodeServices() {
        return new InMemoryAuthorizationCodeServices();
    }
}
